package com.easyadmin.pro.common.handler;

import com.easyadmin.pro.common.enums.HttpCodeEnum;
import com.easyadmin.pro.common.exception.EasyAdminProBaseException;
import com.easyadmin.pro.common.vo.RestResult;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;

/**
 * packageName com.easyadmin.pro.common.handler
 *
 * @author 骑着蚂蚁去上天
 * @version JDK 17
 * @className GlobalExceptionHandler
 * @date 2024/4/1
 * @description 全局异常处理器
 */
@Slf4j
@RestControllerAdvice
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class GlobalExceptionHandler {

    private final HttpServletRequest httpServletRequest;

    /**
     * 缺少请求体异常处理器
     * @param e 缺少请求体异常 使用get方式请求 而实体使用@RequestBody修饰
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public RestResult parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) {
        String requestURI = httpServletRequest.getRequestURI();
        log.error("请求地址'{}',请求体缺失'{}'", requestURI, e.getMessage());
        return RestResult.lose(HttpCodeEnum.SYSTEM_ERROR);
    }

    /**
     * @Description:  捕获请求方法异常，比如post接口使用了get
     */
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public RestResult methodNotAllowedHandler(HttpRequestMethodNotSupportedException e) {
        String requestURI = httpServletRequest.getRequestURI();
        log.error("请求地址'{}',请求方法不被允许'{}'", requestURI, e.getMessage());
        return RestResult.lose(HttpCodeEnum.SYSTEM_ERROR);
    }

    /**
     * get请求的对象参数校验异常
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public RestResult bindExceptionHandler(MissingServletRequestParameterException e) {
        String requestURI = httpServletRequest.getRequestURI();
        log.error("请求地址'{}',get方式请求参数'{}'必传", requestURI, e.getParameterName());
        return RestResult.lose(HttpCodeEnum.SYSTEM_ERROR);
    }

    /**
     * post请求的对象参数校验异常
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public RestResult methodArgumentNotValidHandler(MethodArgumentNotValidException e) {
        String requestURI = httpServletRequest.getRequestURI();
        log.error("请求地址'{}',post方式请求参数异常'{}'", requestURI, e.getMessage());
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        return RestResult.lose(HttpCodeEnum.SYSTEM_ERROR.getCode(), getValidExceptionMsg(allErrors));
    }

    /**
     * 业务类异常
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(EasyAdminProBaseException.class)
    public RestResult businessExceptionHandler(EasyAdminProBaseException e) {
        String requestURI = httpServletRequest.getRequestURI();
        log.error("请求地址'{}',捕获业务类异常'{}'", requestURI,e.getMessage());
        return RestResult.lose(HttpCodeEnum.SYSTEM_ERROR.getCode(), e.getMessage());
    }

    /**
     * 运行时异常
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(RuntimeException.class)
    public RestResult runtimeExceptionHandler(RuntimeException e) {
        String requestURI = httpServletRequest.getRequestURI();
        log.error("请求地址'{}',捕获运行时异常'{}'", requestURI, e.getMessage());
        return RestResult.lose(HttpCodeEnum.SYSTEM_ERROR.getCode(), e.getMessage());
    }

    /**
     * 系统级别异常
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Throwable.class)
    public RestResult throwableExceptionHandler(Throwable e) {
        String requestURI = httpServletRequest.getRequestURI();
        log.error("请求地址'{}',捕获系统级别异常'{}'", requestURI,e.getMessage());
        return RestResult.lose(HttpCodeEnum.SYSTEM_ERROR.getCode(), e.getMessage());
    }


    /**
     * 获取异常消息
     * @param errors
     * @return
     */
    private String getValidExceptionMsg(List<ObjectError> errors) {
        String msg = null;
        if (!CollectionUtils.isEmpty(errors)) {
            StringBuilder sb = new StringBuilder();
            errors.forEach(error -> {
                if (error instanceof FieldError) {
                    sb.append(((FieldError) error).getField()).append(":");
                }
                sb.append(error.getDefaultMessage()).append(";");
            });
            msg = sb.toString();
            msg = msg.substring(0, msg.length() - 1);
        }
        return msg;
    }
}